package it.tcm.TeacherClassMate.writer;

import it.tcm.TeacherClassMate.beans.OrderMainBean;
import it.tcm.TeacherClassMate.beans.OrderRowBean;
import it.tcm.TeacherClassMate.persistent.DBConnection;
import it.tcm.TeacherClassMate.util.OrderRowBeanComparator;
import it.tcm.TeacherClassMate.util.Util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.naming.InitialContext;
import javax.xml.bind.JAXBElement;

import org.apache.log4j.Logger;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Jc;
import org.docx4j.wml.JcEnumeration;
import org.docx4j.wml.ObjectFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.namespace.QName;




public class DocxWriter {
	
	private Logger logger = Logger.getLogger(this.getClass().getName());
	private final String XPATH_TO_SELECT_MATH_NODES_2 = "//m:oMathPara";
	private final String XPATH_TO_SELECT_MATH_NODES = "w:p[w:pPr/w:pStyle/@w:val='Formula']";
	
	@SuppressWarnings("unchecked")
	public boolean createDocx(OrderMainBean omb)  {
	
		 // recupero il documento docx per aggiungere le equazioni e poi salvarlo
		 try {
			 javax.naming.Context ctx = new InitialContext();
			 String docxFileDir = (String)ctx.lookup("java:comp/env/docxPath");
			 DBConnection db = new DBConnection();
			 Connection conn = db.getDBConnection();
			 Statement stmt = conn.createStatement();
			 ResultSet rs = stmt.executeQuery("select docx from ORDERMAIN where id = " + omb.getId());
			 InputStream inputStream = null;
			 Blob docxblob = null;
			 if (rs.next()) {
				  docxblob = rs.getBlob(1);
				  if (docxblob != null) {
					  inputStream = docxblob.getBinaryStream();
				  }
			 }  		
			 WordprocessingMLPackage docx = WordprocessingMLPackage.load(inputStream);			 
			 MainDocumentPart documentPart = docx.getMainDocumentPart();
			 String xpath = "//w:p";
			 List<Object> listp = documentPart.getJAXBNodesViaXPath(xpath, false);
			 		
		     List<org.docx4j.wml.P> arrayOfParag = new ArrayList<org.docx4j.wml.P>();
				
			 for (Object obj : listp) {
					org.docx4j.wml.P para0 = (org.docx4j.wml.P)obj;
					List<Object> listr = para0.getContent();
					if (listr != null && listr.size() != 0) {
						arrayOfParag.add(para0);
					}
			 }
			 
			 ObjectFactory factory = Context.getWmlObjectFactory();
			 
			 org.docx4j.wml.P p0 = factory.createP();
			 org.docx4j.wml.Text t0 = factory.createText();
			 t0.setValue("");
			 org.docx4j.wml.R r0 = factory.createR();
			 r0.getContent().add(t0);
			 p0.getContent().add(r0);
			 arrayOfParag.add(p0);
			 
			 // devo fare il merge dei docx delle equazioni			 
			 ArrayList<OrderRowBean> array  = new ArrayList<OrderRowBean>(omb.getOrderRows()); 
			 Collections.sort(array,new OrderRowBeanComparator());
			 
			 for (OrderRowBean ob : array)  {
				 
				 String table = null;
				 String id = ob.getIdForm().toString();
				 if (ob.getIdTypology().equals(Util.EQUATIONS_TYPOLOGY)) {
					 table = Util.EQUATION; 
				 } else {
					 //....
				 }
				 
				 // recupero il documento da blob
				 Blob image = null;
				 stmt = conn.createStatement();
				 rs = stmt.executeQuery("select docx from " + table + " where id = " + id);
				 InputStream indoc = null;
				 if (rs.next()) {
				    image = rs.getBlob(1);
				    if (image != null) {
					  indoc = image.getBinaryStream();
				    } else {					  
					  //take it from file
				       File file = null;
					   if (table.equals("EQUATION")) {
							String equationDocxFileDir = docxFileDir + "//E//";
							file = new File(equationDocxFileDir + "E" + id + ".docx");
					   }
					   indoc = new FileInputStream(file);	
				    }		
				 }
				 
				 WordprocessingMLPackage formula = WordprocessingMLPackage.load(indoc);
				 MainDocumentPart documentPartFormula = formula.getMainDocumentPart();
				 List<Object> listpformula = documentPartFormula.getJAXBNodesViaXPath(xpath, false);				
				 for (Object obj : listpformula) {
						org.docx4j.wml.P para0 = (org.docx4j.wml.P)obj;
						List<Object> listr = para0.getContent();
						if (listr != null && listr.size() != 0) {
							arrayOfParag.add(para0);
						}
				 }
				 
				 List<Object> listequa = documentPartFormula.getJAXBNodesViaXPath(XPATH_TO_SELECT_MATH_NODES_2, false);
				 org.docx4j.math.CTOMathPara m0 = null;
				 
				 for (Object obj : listequa) {
					   logger.info("obj class " + obj.getClass().getName());
					   JAXBElement<org.docx4j.math.CTOMathPara> cto = (JAXBElement<org.docx4j.math.CTOMathPara>)obj;
					   //m0 = (org.docx4j.math.CTOMath)obj;
					   m0 = cto.getValue();
					   
				 }
				
				 JAXBContext contextObj = JAXBContext.newInstance(org.docx4j.math.CTOMathPara.class);

				 Marshaller marshallerObj = contextObj.createMarshaller();
				 marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
				 long iDateTime = new Date().getTime();
				 File fileformula = new File(docxFileDir + "//formula_"+ String.valueOf(iDateTime) + ".xml");
				 FileOutputStream fileforumlaoutputsteam = new FileOutputStream(fileformula);
				 //marshallerObj.marshal(m0.getParent(), new FileOutputStream(fileformula));
				 
				 marshallerObj.marshal(new JAXBElement<org.docx4j.math.CTOMathPara>(new QName("uri","local"), org.docx4j.math.CTOMathPara.class, m0), fileforumlaoutputsteam);

				 if (ob.getPoints() != null)  { 
					 // Create the paragraph 4 punteggio
					 org.docx4j.wml.P para= factory.createP();
					 // Create the text element
					 org.docx4j.wml.Text t= factory.createText();		
					 t.setValue("Punteggio assegnato all'esercizio : " + ob.getPoints());
				     org.docx4j.wml.Color color =factory.createColor();
		             color.setVal("FF0000");
		             org.docx4j.wml.R run = factory.createR();
		             org.docx4j.wml.RPr rpr = factory.createRPr();
		             rpr.setColor(color);
	                run.setRPr(rpr);
	                run.getContent().add(t);
	                Jc jc = Context.getWmlObjectFactory().createJc();
	                jc.setVal(JcEnumeration.RIGHT);
	                org.docx4j.wml.PPr ppr = factory.createPPr();
	                ppr.setJc(jc);
	                para.setPPr(ppr);
	                para.getContent().add(run);      			
					 arrayOfParag.add(para);
				 }
				 indoc.close();
				 fileforumlaoutputsteam.close();
				 fileformula.delete();
				 logger.debug("fileformula " + docxFileDir + "//formula_"+ String.valueOf(iDateTime) + ".xml deleted");
			 }
			 
			 // Create the package
		     WordprocessingMLPackage wordMLPackage = new WordprocessingMLPackage();
			 // Create the main document part (word/document.xml)
			 MainDocumentPart wordDocumentPart = new MainDocumentPart();
			 org.docx4j.wml.Body body = factory.createBody();
			 body.getContent().addAll(arrayOfParag);
			 org.docx4j.wml.Document wmlDocumentEl = factory .createDocument();
		     wmlDocumentEl.setBody(body);
			 // Put the content in the part
			 wordDocumentPart.setJaxbElement(wmlDocumentEl);
			 wordMLPackage.addTargetPart(wordDocumentPart);
			 long lDateTime = new Date().getTime();
			 File filedocx = new File(docxFileDir + "//verif_"+ String.valueOf(lDateTime) + ".docx");
			 wordMLPackage.save(filedocx);
			 FileInputStream fisdocx = new FileInputStream(filedocx);
			 
			
			 String sql = "update ORDERMAIN set docx = ? WHERE id = ?";
			 PreparedStatement stmt0 = conn.prepareStatement(sql);    
			 stmt0.setInt(2, omb.getId());    
			 logger.info("fisdo avaliable" + fisdocx.available());  
			 logger.info("filedocx.length()" + filedocx.length());   		    	   
			 stmt0.setBinaryStream(1, fisdocx, (int) filedocx.length()); // ri-metto il docx				 
			 stmt0.execute();
			 fisdocx.close();
			 conn.close();
			 filedocx.delete();
			 
		 } catch(Exception e) {
			 logger.error("Exception e " + e.getMessage());
			 e.printStackTrace();
		 }

	  
	 return true;
	  
   }

}
